#!/usr/bin/perl
#
# (C) Copyright 2010- Hewlett-Packard Development Company, L.P.
# 
#  $Id: instance_template 18812 2012-06-19 07:17:25Z yi.wang4@hp.com $
#

package InstStorage;

use strict;
use 5.008000;
use warnings;

use XML::Twig;
use FileHandle;

use lib '/opt/hp/nv/lib/perl';
use config qw/$nvpath/;
use instance ':all';

our $GOOD = 1;
our $BAD = 0;

sub new
{
    my $proto = shift;

    my $class = ref($proto) || $proto;
    my $self = {};

    $self->{INSTANCEID} = shift;
    $self->{INSTANCEMSA} = shift;

    $self->{MSAS} = [];
    $self->{ERRORSTR} = "";

    bless ($self, $class);

    return $self;
}

sub __setError($$)
{
    my $self = shift;
    $self->{ERRORSTR} = shift;
}

sub GetErrorStr($)
{
    my $self = shift;
    return $self->{ERRORSTR};
}

sub Build($)
{
    my $self = shift;

    my @users = get_instance_user_list($self->{INSTANCEID});

    if (@users == 0) {
        $self->__setError("Invalid instance conf, no users");
        return $BAD;
    }

    my $raid = get_instance_storagetype($users[0]);
    my @racks = get_instance_racklist($users[0]);

    my $twig = new XML::Twig;
    $twig->parsefile($self->{INSTANCEMSA} . ".xml");
    my $twig_root = $twig->root;

    my $volnum = 0;
    for my $rack(@racks) {
        my @msas = get_msas_in_rack($rack);
        for my $index (0 .. $#msas) {
            my $msa_config = main::get_msa_config($raid, $index);

            my $msa_elt;
            for my $config_elt ($twig_root->children) {
                if ($config_elt->att("name") eq $msa_config) {
                    $msa_elt = $config_elt->copy;
                    last;
                }
            }
            if (!$msa_elt) {
                $self->__setError("Invalid config $msa_config");
                return $BAD;
            }

            $msa_elt->set_gi("msa");
            $msa_elt->set_att("name", $msas[$index]);

            # check whether slot of vdisk is valid
            for my $vdisk_elt ($msa_elt->children) {
                my $slot = $vdisk_elt->att("slot");

                # this only a test, need to change
#                if ($slot =~ /(21|22|23|24)/) {
#                    $vdisk_elt->delete;
#                    next;
#                }

                for my $vol_elt($vdisk_elt->children) {
                    if (!$vol_elt->att("name") 
                       || length($vol_elt->att("name"))==0) {
                        $volnum++;
                        my $volname = sprintf("%s_%03d", 
                                      $vdisk_elt->att("name"), $volnum);
                        $vol_elt->set_att("name", $volname);
                    }
                }
            }
            push @{$self->{MSAS}}, $msa_elt;
        }
    }

    return $GOOD;
}

sub PrintToXml($)
{
    my $self = shift;

    my $fh = new FileHandle;
    if (!$fh->open("> $nvpath/lib/instancestorage_$self->{INSTANCEID}.xml")) {
        $self->__setError("Cannot create instancestorage file for " 
                          . $self->{INSTANCEID});
        return $BAD;
    }

    my $configtype = get_inst_config_type();
    print $fh "<?xml version=\"1.0\"?>\n"
            . "<instance_storage type=\"$configtype\">\n";

    for my $msa_elt (@{$self->{MSAS}}) {
        $msa_elt->print($fh, "indented");
    }

    print $fh "</instance_storage>\n";
    $fh->close;
    return $GOOD;
}

package InstMapping;

use strict;
use 5.008000;
use warnings;

use lib '/opt/hp/nv/lib/perl';
use config qw/$nvpath/;
use instance ':all';

our $GOOD = 1;
our $BAD = 0;

my $PERMISSION = "0775";
my $GROUP = "seaquest";

sub new
{
    my $proto = shift;

    my $class = ref($proto) || $proto;
    my $self = {};

    $self->{INSTANCEID} = shift;
    $self->{INSTANCEMSA} = shift;

    $self->{MSAS} = [];
    $self->{ERRORSTR} = "";

    bless ($self, $class);

    return $self;
}

sub __setError($$)
{
    my $self = shift;
    $self->{ERRORSTR} = shift;
}

sub GetErrorStr($)
{
    my $self = shift;
    return $self->{ERRORSTR};
}

sub Build($)
{
    my $self = shift;

    my $configtype = get_inst_config_type();

    my @users = get_instance_user_list($self->{INSTANCEID});

    if (@users == 0) {
        $self->__setError("Invalid instance conf, no users");
        return $BAD;
    }

    my $raid = get_instance_storagetype($users[0]);
    my @racks = get_instance_racklist($users[0]);

    for my $rack(@racks) {
        my @msas = get_msas_in_rack($rack);

        for my $index (0 .. $#msas) {
            my $msaname = lc $msas[$index];
            my $msa = {name => $msaname, 
                       type => "$configtype",
                       config => main::get_msa_config($raid, $index)
                      };

            for my $username (@users) {
                my $user = { name => $username, 
                             permission => $PERMISSION,
                             group => $GROUP
                           };
                push @{$msa->{USERS}}, $user;
            }

            push @{$self->{MSAS}}, $msa;
        }
    }

    return $GOOD;
}

sub PrintToXml($)
{
    my $self = shift;

    if (!open(FH, "> $nvpath/lib/instancemapping_$self->{INSTANCEID}.xml")) {
        $self->__setError("Cannot create instancemapping file for " 
                          . $self->{INSTANCEID});
        return $BAD;
    }

    print FH "<?xml version=\"1.0\"?>\n";
    print FH "<instance_mapping instancemsa=\"$self->{INSTANCEMSA}\">\n";
    for my $msa (@{$self->{MSAS}}) {
        print FH "  <msa name=\"$msa->{name}\""
               . " config=\"$msa->{config}\""
               . " type=\"$msa->{type}\">\n";
        for my $user (@{$msa->{USERS}}) {
            print FH "    <user name=\"$user->{name}\">\n";
            print FH "      <permission>$user->{permission}</permission>\n";
            print FH "      <group>$user->{group}</group>\n";
            print FH "    </user>\n";
        }
        print FH "  </msa>\n";
    }
    print FH "</instance_mapping>\n";
    close FH;

    return $GOOD;
}

package main;

use POSIX;
use Getopt::Long; 
use File::Basename;

use lib '/opt/hp/nv/lib/perl';
use config ':all';
use instance ':all';

# possible error returns
use constant {
    OK => 0,
    WARN => 1,
    CRITICAL => 2,
    UNKNOWN => 3,
};

# Global variables

# common global variables
my $proceed=1;
my $done=0;

my $myscriptname = "createinststorage";
my $status_file = "$nvpath/instance/status/" . $myscriptname . '.stat';
my $revision = '$Revision: 18812 $';
$revision =~ s/\$//g;

# script specific globals

# command line options
my %gv_opts;

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#
# Attention Template Users:
#  Subs marked with a header "DO NOT DELETE/DO NOT MODIfY" should not be removed as
#  these routines are required in the script
#  Subs marked with a header "CHANGE FOR YOUR NEEDS" should be modified
#  as required to suit the individual needs of your script
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# DO NOT DELETE/DO NOT MODIFY
#
# This sub calls module routine to log informational message to log file
# after first prepending program name; timestamp will be added in
# Perl module
#
sub log_msg
{
    my $message = shift;
    my $infomessage;

    $infomessage = basename($0) . ": INFO: ". $message . "\n";
    instance_log_event($infomessage);

}

# DO NOT DELETE/DO NOT MODIFY
#
# This sub calls module routine to log warning message to log file
# after first prepending program name and Warning label; a timestamp 
# will be added in Perl module
#
sub log_warn
{
    my $message = shift;
    my $warnmessage;

    $warnmessage = basename($0) . ": WARNING: ". $message . "\n";
    instance_log_event($warnmessage);

}

# DO NOT DELETE/DO NOT MODIFY
#
# This sub calls module routine to log error message to log file
# after first prepending program name; timestamp will be added in
# Perl module; the program will then exit
#
sub logerr_n_die
{
    my $message = shift;
    my $errormessage;

    $errormessage = basename($0) . ": ERROR: ". $message . "\n";
    print STDERR $errormessage;
    
    instance_log_event($errormessage);
    exit(CRITICAL);

}

# CHANGE FOR YOUR NEEDS
#
# This sub checks for any requirements that must be met before 
# the configuration is performed.
#
sub pre_req_check
{
    return(OK);
}

# CHANGE FOR YOUR NEEDS
#
# This sub verifies that the work done is complete and in such a state 
# that it is ready for the next step to be done
#
sub post_check
{
    return(OK);
}

# CHANGE FOR YOUR NEEDS
#
# This sub checks the script status to determine whether 
# the script has already been run successfully.
# The status file could just hold "completed", for example,
# or it could hold a count of how many things were processed last time,
# e.g. number of nodes, or number of disks, etc.  So that a comparison
# can be made to see if processing must be done again.
#
sub get_status(;$)
{
    my $prefix = shift;
    $prefix = '' unless (defined $prefix);
        
    # Keep the open and close of the file along with the line processing

    # if we haven't yet written this file then we surely must proceed
    return($proceed) if (!-e $status_file);

    open(IFH,$status_file) || logerr_n_die("Can't open file $status_file: $!");
    while (<IFH>) # loop through the whole file
    {
        next if (/^\s*$/);
        next if (/^\#/);

        # ADD HERE THE PROCESSING THAT MAKES SENSE FOR YOUR CODE!
        # IN THIS EXAMPLE WE CHECK FOR 'completed'
        if (/^$prefix:completed/) {
            close(IFH);
            return($done);
        }
    }

    close(IFH);
    return($proceed);
}

# CHANGE FOR YOUR NEEDS
#
# This sub sets the script status to be examined
# the next time the script is run.
# The status file could just hold "completed", for example,
# or it could hold a count of how many things were processed last time,
# e.g. number of nodes, or number of disks, etc.  So that a comparison
# can be made to see if processing must be done again.
#
sub set_status($;$)
{
    my ($statusmsg, $prefix) = @_;       

    return if ($gv_opts{test});
 
    # Keep the open and close of the file
    open(OFH,">>$status_file") || logerr_n_die("Can't open file $status_file: $!");

    # ADD HERE THE PROCESSING THAT MAKES SENSE FOR YOUR CODE!
    print OFH "$prefix:$statusmsg\n";

    close(OFH);

}

sub get_msa_config($$)
{
    my $raid = shift;
    my $index = shift;

    my $msa_config;
    if ($raid eq "NRAID") {
        if ($index == 0) {$msa_config = "two";}
        else {$msa_config = "three";}
    }
    elsif ($raid eq "RAID5") {
        if ($index % 2 == 0) {$msa_config = "four";}
        else {$msa_config = "five";}
    }

    return $msa_config;
}


sub create_inststorage($$)
{
    my $inst_id = shift;
    my $instancemsa = shift;

    my $inststorage = new InstStorage($inst_id, $instancemsa);

    logerr_n_die($inststorage->GetErrorStr()) if (!$inststorage->Build());
    logerr_n_die($inststorage->GetErrorStr()) if (!$inststorage->PrintToXml());
}

sub create_instmapping($$)
{
    my $inst_id = shift;
    my $instancemsa = shift;

    my $instmapping = new InstMapping($inst_id, $instancemsa);

    logerr_n_die($instmapping->GetErrorStr()) if (!$instmapping->Build());
    logerr_n_die($instmapping->GetErrorStr()) if (!$instmapping->PrintToXml());
}

# CHANGE FOR YOUR NEEDS
#
# This sub verifies that the work done is complete and in such a state 
# that it is ready for the next step to be done
#
sub perform_config
{
    # Keep the following checks to determine whether the
    # script is being forced to be re-run, and to check
    # whether this script completed successfully
    my $force_flag = get_force_flag();

    # CHANGE PREFIX TO USERID OR INSTANCEID OR ELSE
    my $prefix = "";  
    my $status_value = get_status($prefix);

    return(OK) if (!$force_flag && ($status_value == $done));
	
    my $size = get_msatypes_filename();
    $size =~ s/.*[^\d](\d+)GB$/$1/;

    my $instancemsa = "$nvpath/lib/instancemsa_${size}gb";

    my @inst_ids = get_instance_id_list();
    for my $inst_id (@inst_ids) {
        create_instmapping($inst_id, $instancemsa);
        create_inststorage($inst_id, $instancemsa);
    }

#    set_status("completed", $prefix);
    return(OK);
}

# CHANGE FOR YOUR NEEDS
# 	define what your script does.
#
# usage
#
sub usage
{
print <<"EOF";

This script will create the instancemap xml file for all instances.

$myscriptname --help

EOF

exit(UNKNOWN);
}



### Main ###

# DO NOT DELETE/DO NOT MODIFY
#
# Do not delete any of the following subroutine calls.  
# You can add more code to perform_config
#

# The only option supported right now is help
# generate usage output for anything else.
&GetOptions( \%gv_opts,
             "test",
             "help"=> \&usage) or usage(); 

log_msg("Starting script: revision number $revision");

pre_req_check;

perform_config;

post_check;

# Return success 
exit(OK);
